#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@file: box_type.py
@time: 2024-06-25 11:27
@desc:
"""
import traceback
from urllib.parse import urlencode

import pandas as pd
from io import BytesIO

from common_tools import apply_formatting
from tools import log_operations, token_required, get_images_df, excel_to_images
from flask import Blueprint, request, jsonify, send_file
from global_scope import MAX_PAGE_SIZE, get_db, images_sheet_name
from project_model import BoxType, Image
from global_scope import box_types_sheet_name
from tools import excel_to_box_types, get_box_types_df

db = get_db()
box_type_bp = Blueprint('box_type', __name__, url_prefix='/box_types')


@box_type_bp.route('', methods=['POST'])
@log_operations
@token_required
def add_box_type():
    data = request.json
    typeName = data.get('typeName')
    length = data.get('length')
    box_type_value = data.get('box_type')
    box_code = data.get('box_code')
    full_name = data.get('full_name')
    image_ids = data.get('image_ids', [])

    if not typeName or not length or not box_type_value or not box_code or not full_name:
        return jsonify({"code": 1, "message": "typeName, length, box_type, box_code and full_name are required"}), 400

    box_type = BoxType.query.filter_by(typeName=typeName).first()
    if not box_type:
        remark = ""
        if 'remark' in data:
            remark = data['remark']

        box_type = BoxType(type_name=typeName, remark=remark)
        box_type.length = length
        box_type.box_type = box_type_value
        box_type.box_code = box_code
        box_type.full_name = full_name
        db.session.add(box_type)
        db.session.commit()

    if image_ids:
        images = Image.query.filter(Image.id.in_(image_ids)).all()
        box_type.images.extend(images)
        db.session.commit()

    return jsonify({"code": 0, "message": "BoxType added successfully", "data": box_type.id}), 201


@box_type_bp.route('/<int:box_type_id>', methods=['PATCH'])
@log_operations
@token_required
def update_box_type(box_type_id):
    data = request.json
    box_type = BoxType.query.get(box_type_id)
    if not box_type:
        return jsonify({"code": 1, "message": "BoxType not found"}), 404

    if 'typeName' in data:
        box_type.typeName = data['typeName']
    if 'length' in data:
        box_type.length = data['length']
    if 'box_type' in data:
        box_type.box_type = data['box_type']
    if 'box_code' in data:
        box_type.box_code = data['box_code']
    if 'full_name' in data:
        box_type.full_name = data['full_name']
    if 'remark' in data:
        box_type.remark = data['remark']
    if 'images' in data:
        image_ids = [c.get('id') for c in data['images'] if c.get('id')]
        images = Image.query.filter(Image.id.in_(image_ids)).all()
        box_type.images = images

    db.session.commit()

    return jsonify({"code": 0, "message": "BoxType updated successfully"}), 200


@box_type_bp.route('/<int:box_type_id>', methods=['DELETE'])
@log_operations
@token_required
def delete_box_type(box_type_id):
    box_type = BoxType.query.get(box_type_id)
    if not box_type:
        return jsonify({"code": 1, "message": "BoxType not found"}), 404

    db.session.delete(box_type)
    db.session.commit()

    return jsonify({"code": 0, "message": "BoxType deleted successfully"}), 200


@box_type_bp.route('', methods=['GET'])
@log_operations
@token_required
def get_box_types():
    type_name = request.args.get('typeName', None)
    page_no = int(request.args.get('pageNo', 1))
    page_size = int(request.args.get('pageSize', MAX_PAGE_SIZE))

    if type_name:
        box_types_query = BoxType.query.filter(BoxType.typeName.contains(type_name))
    else:
        box_types_query = BoxType.query

    # 使用paginate方法进行分页
    pagination = box_types_query.paginate(page=page_no, per_page=page_size, error_out=False)
    box_types = pagination.items

    # 准备响应数据
    data = {
        "pageData": [
            {
                "id": bt.id,
                "typeName": bt.typeName,
                "length": bt.length,
                "box_type": bt.box_type,
                "box_code": bt.box_code,
                "full_name": bt.full_name,
                "remark": bt.remark,
                "createTime": bt.createTime.isoformat(),
                "updateTime": bt.updateTime.isoformat(),
                "images": [{"id": img.id, "imageUrl": img.imageUrl} for img in bt.images],
                "show_name": f"{bt.typeName}|{bt.box_code}|{bt.length}|{bt.box_type}"
            } for bt in box_types
        ],
        "total": pagination.total
    }

    # 构造原始URL，包括分页和其他查询参数
    encoded_query_params = urlencode(request.args)
    origin_url = f"{request.base_url}?{encoded_query_params}"

    return jsonify({
        "code": 0,
        "message": "OK",
        "data": data,
        "originUrl": origin_url
    }), 200


@box_type_bp.route('/upload', methods=['POST'])
@log_operations
@token_required
def upload_box_types():
    if 'file' not in request.files:
        return jsonify({"code": 1, "message": "No file part"}), 400

    file = request.files['file']
    if file.filename == '':
        return jsonify({"code": 1, "message": "No selected file"}), 400

    try:
        excel_to_images(file, request)
        new_types, updated_types = excel_to_box_types(file, request)
        return jsonify({
            "code": 0,
            "message": f"Box types uploaded successfully: {new_types} added, {updated_types} updated"
        }), 201
    except Exception as e:
        tb = traceback.format_exc()
        request.trace_logger.error(f"Exception occurred: {str(e)}\n{tb}")
        return jsonify({"code": 1, "message": str(e)}), 500


@box_type_bp.route('/download', methods=['GET'])
@log_operations
@token_required
def download_box_types():
    output = BytesIO()
    with pd.ExcelWriter(output, engine='openpyxl') as writer:
        df_objs = [
            (get_images_df(), images_sheet_name),
            (get_box_types_df(), box_types_sheet_name),
        ]
        # 写入数据
        for df, sheet_name in df_objs:
            df.to_excel(writer, index=False, sheet_name=sheet_name)
            apply_formatting(writer.sheets[sheet_name], df)
    output.seek(0)

    return send_file(output, download_name="BoxTypes.xlsx", as_attachment=True)
